import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

# 初始化画布
fig, ax = plt.subplots(figsize=(10, 8))
plt.subplots_adjust(bottom=0.25)  # 为滑块预留空间

# 定义计算电场矢量的函数
def electric_field(q, x0, y0, X, Y):
    """计算点电荷在 (x0, y0) 处产生的电场矢量场"""
    r = np.sqrt((X - x0)**2 + (Y - y0)**2)
    r[r == 0] = 1e-10  # 避免除以零
    Ex = q * (X - x0) / r**3
    Ey = q * (Y - y0) / r**3
    return Ex, Ey

# 生成网格
x = np.linspace(-5, 5, 20)
y = np.linspace(-5, 5, 20)
X, Y = np.meshgrid(x, y)

# 初始电荷参数
q_init = 1.0
x0_init = 0.0
y0_init = 0.0

# 计算初始电场
Ex, Ey = electric_field(q_init, x0_init, y0_init, X, Y)

# 绘制矢量场
quiver = ax.quiver(X, Y, Ex, Ey, color='blue', scale=30)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_title('点电荷电场矢量场 (可交互)')

# 添加电荷位置标记
charge_marker, = ax.plot(x0_init, y0_init, 'ro', markersize=10, label=f'电荷量: {q_init}')
ax.legend()

# 添加滑块控件
ax_q = plt.axes([0.25, 0.15, 0.65, 0.03])  # 电荷量滑块位置
ax_x = plt.axes([0.25, 0.10, 0.65, 0.03])  # X位置滑块位置
ax_y = plt.axes([0.25, 0.05, 0.65, 0.03])  # Y位置滑块位置

slider_q = Slider(ax_q, 'Q', -5.0, 5.0, valinit=q_init)
slider_x = Slider(ax_x, 'X', -4.0, 4.0, valinit=x0_init)
slider_y = Slider(ax_y, 'Y', -4.0, 4.0, valinit=y0_init)

# 添加重置按钮
reset_ax = plt.axes([0.8, 0.02, 0.1, 0.04])
reset_button = Button(reset_ax, '重置', color='lightgoldenrodyellow')

# 更新函数
def update(val):
    q = slider_q.val
    x0 = slider_x.val
    y0 = slider_y.val
    
    # 重新计算电场
    Ex, Ey = electric_field(q, x0, y0, X, Y)
    
    # 更新矢量场
    quiver.set_UVC(Ex, Ey)
    
    # 更新电荷标记
    charge_marker.set_data(x0, y0)
    charge_marker.set_label(f'电荷量: {q:.1f}')
    ax.legend()
    
    fig.canvas.draw_idle()

# 绑定滑块事件
slider_q.on_changed(update)
slider_x.on_changed(update)
slider_y.on_changed(update)

# 重置函数
def reset(event):
    slider_q.reset()
    slider_x.reset()
    slider_y.reset()

reset_button.on_clicked(reset)

plt.show()